package cn.turboinfo.dongying.api.domain.util;

import cn.turboinfo.dongying.api.entity.common.pojo.geo.CoordinateEntity;
import lombok.val;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LinearRing;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.io.ParseException;
import org.locationtech.jts.io.WKBReader;
import org.locationtech.jts.io.WKBWriter;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author gadzs
 * @description
 * @date 2023/8/25 14:46
 */
public class CoordinateUtils {

    /**
     * 坐标数组转Polygon byte[]
     * POLYGON 是一种特定的几何类型，它用于表示平面上的封闭多边形。一个 POLYGON 数据字段只能存储多边形类型的几何形状，而不能存储其他类型的几何数据，如点或线。
     * GEOMETRY 是一种通用的空间数据类型，它可以用来表示各种不同类型的几何形状，包括点（Point）、线（LineString）、多边形（Polygon）、多点（MultiPoint）、多线（MultiLineString）、多多边形（MultiPolygon）等。GEOMETRY 类型的字段可以存储任意类型的几何形状。
     * X 是经度，Y 是纬度
     *
     * @param coordinateEntityList
     * @return
     */
    public static byte[] getPolygonBytes(List<CoordinateEntity> coordinateEntityList) {
        // 坐标数组
        List<Coordinate> coordinates = getCoordinates(coordinateEntityList);

        // 创建GeometryFactory
//        GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null);
//
//        // 创建线性环
//        Coordinate[] coordinatesArray = coordinates.toArray(new Coordinate[0]);
//        Polygon polygon = geometryFactory.createPolygon(coordinatesArray);

        // 使用坐标数组创建一个 LinearRing 对象
        GeometryFactory geometryFactory = new GeometryFactory();
        LinearRing linearRing = geometryFactory.createLinearRing(coordinates.toArray(new Coordinate[0]));

        // 使用 LinearRing 创建一个 Polygon 对象
        Polygon polygon = geometryFactory.createPolygon(linearRing);
        WKBWriter wkbWriter = new WKBWriter();
        byte[] wkbBytes = wkbWriter.write(polygon);
        return wkbBytes;
    }

    /**
     * byte[]转换成Polygon
     *
     * @param boundary
     * @return
     */
    public static Polygon getPolygon(byte[] boundary) throws ParseException {
        // 坐标数组
        // 使用 WKBReader 将字节数组解码为 JTS Polygon 对象
        WKBReader wkbReader = new WKBReader();
        Polygon polygon = (Polygon) wkbReader.read(boundary);
        return polygon;
    }

    public static List<Coordinate> getCoordinates(List<CoordinateEntity> coordinateEntityList) {
        // 坐标数组
        List<Coordinate> coordinates = new ArrayList<>();
        coordinateEntityList.forEach(coordinateEntity -> {
            coordinates.add(new Coordinate(coordinateEntity.getLongitude().doubleValue(), coordinateEntity.getLatitude().doubleValue()));
        });
        if (coordinates.size() == 0) {
            return coordinates;
        }
        //判断第一个点和最后一个点是否相同
        if (!coordinates.get(0).equals(coordinates.get(coordinates.size() - 1))) {
            //首尾连接
            coordinates.add(coordinates.get(0));
        }
        return coordinates;
    }

    /**
     * byte[]转换成坐标数组
     *
     * @param boundary
     * @return
     */
    public static List<CoordinateEntity> getCoordinateList(byte[] boundary) throws ParseException {
        List<CoordinateEntity> coordinateEntityList = new ArrayList<>();
        Polygon polygon = getPolygon(boundary);
        Arrays.stream(polygon.getCoordinates()).forEach(coordinate -> {
            CoordinateEntity coordinateEntity = new CoordinateEntity();
            coordinateEntity.setLongitude(new BigDecimal(coordinate.getX()));
            coordinateEntity.setLatitude(new BigDecimal(coordinate.getY()));
            coordinateEntityList.add(coordinateEntity);
        });
        coordinateEntityList.remove(coordinateEntityList.size() - 1);
        return coordinateEntityList;
    }

    /**
     * 计算多边形中心点
     *
     * @param coordinates
     * @return
     */
    public static Coordinate calculateCenter(List<Coordinate> coordinates) {
        double sumX = 0;
        double sumY = 0;

        for (Coordinate coord : coordinates) {
            sumX += coord.x;
            sumY += coord.y;
        }

        double centerX = sumX / coordinates.size();
        double centerY = sumY / coordinates.size();

        return new Coordinate(centerX, centerY);
    }

    /**
     * 计算多边形中心点
     *
     * @param coordinates
     * @return
     */
    public static CoordinateEntity calculateEntityCenter(List<CoordinateEntity> coordinates) {
        BigDecimal sumX = BigDecimal.ZERO;
        BigDecimal sumY = BigDecimal.ZERO;

        for (CoordinateEntity coord : coordinates) {
            sumX = sumX.add(coord.getLongitude());
            sumY = sumY.add(coord.getLatitude());
        }

        BigDecimal centerX = sumX.divide(BigDecimal.valueOf(coordinates.size()));
        BigDecimal centerY = sumY.divide(BigDecimal.valueOf(coordinates.size()));
        return new CoordinateEntity(centerX, centerY);
    }

    /**
     * 计算两个坐标点的距离
     *
     * @param coordinates
     * @return
     */
    public static double getDistance(CoordinateEntity[] coordinates) {

        val lng1 = coordinates[0].getLongitude();
        val lat1 = coordinates[0].getLatitude();
        val lng2 = coordinates[1].getLongitude();
        val lat2 = coordinates[1].getLatitude();

        return getDistance(lng1, lat1, lng2, lat2);

    }

    /**
     * 计算两个坐标点的距离
     *
     * @param lng1
     * @param lat1
     * @param lng2
     * @param lat2
     * @return
     */
    public static double getDistance(BigDecimal lng1, BigDecimal lat1, BigDecimal lng2, BigDecimal lat2) {

//        GeometryFactory factory = new GeometryFactory(new PrecisionModel(PrecisionModel.maximumPreciseValue), 4326);

//        Point point1 = factory.createPoint(new Coordinate(lng1.doubleValue(), lat1.doubleValue()));
//        Point point2 = factory.createPoint(new Coordinate(lng2.doubleValue(), lat2.doubleValue()));
        // 使用地球平均半径，约为 6371 公里
        double earthRadiusKm = 6371;
//        return DistanceOp.distance(point1, point2) * earthRadiusKm * 1000; // 转换为米;
        //return degreesToKilometers(distance);


        BigDecimal radLat1 = MathUtils.caleRadian(lat1);
        BigDecimal radLat2 = MathUtils.caleRadian(lat2);
        BigDecimal latitudeDiff = radLat1.subtract(radLat2);
        BigDecimal longitudeDiff = MathUtils.caleRadian(lng1).subtract(MathUtils.caleRadian(lng2));

        double distance = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(latitudeDiff.doubleValue() / 2), 2) + Math.cos(radLat1.doubleValue()) * Math.cos(radLat2.doubleValue()) * Math.pow(Math.sin(longitudeDiff.doubleValue() / 2), 2)));

        return distance * earthRadiusKm * 1000;

    }


    public static double getDistanceKm(CoordinateEntity[] coordinates) {
        return getDistance(coordinates) / 1000;
    }

    public static double getDistanceKm(BigDecimal lng1, BigDecimal lat1, BigDecimal lng2, BigDecimal lat2) {
        return getDistance(lng1, lat1, lng2, lat2) / 1000;
    }

    public static double degreesToKilometers(double degrees) {
        // 使用地球平均半径，约为 6371 公里
        double earthRadiusKm = 6371;
        return degrees * (Math.PI / 180) * earthRadiusKm;
    }
}
